package com.wash.shoes.interceptor;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.wash.shoes.annotation.DataPermission;
import com.wash.shoes.context.DataPermissionContext;
import com.wash.shoes.factory.DataPermissionHandlerFactory;
import com.wash.shoes.handler.DataPermissionHandler;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.Map;

/**
 * 自定义数据权限拦截器（使用InnerInterceptor）
 */
@Component
public class DataPermissionInterceptor implements InnerInterceptor {
    @Autowired
    private DataPermissionHandlerFactory dataPermissionHandlerFactory;

    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
                            ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        // 获取Mapper接口方法
        String id = ms.getId();
        String className = id.substring(0, id.lastIndexOf('.'));
        String methodName = id.substring(id.lastIndexOf('.') + 1);

        Class<?> mapperClass = null;
        try {
            mapperClass = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
        Method[] methods = mapperClass.getDeclaredMethods();

        DataPermission dataPermission = null;
        for (Method method : methods) {
            //
            if (method.getName().equals(methodName) /*&& method.getParameterCount() == getParameterCount(parameter)*/) {
                dataPermission = method.getAnnotation(DataPermission.class);
                break;
            }
        }

        // 如果方法上有数据权限注解
        if (dataPermission != null) {
            // 构建数据权限信息
            DataPermissionContext.DataPermissionInfo info = new DataPermissionContext.DataPermissionInfo(
                    dataPermission.type(),
                    dataPermission.field(),
                    dataPermission.tableAlias()
            );

            // 设置数据权限上下文
            DataPermissionContext.setDataPermissionInfo(info);

            try {
                // 处理数据权限
                String permissionSql = processDataPermission(info);

                // 修改SQL
                if (permissionSql != null && !permissionSql.isEmpty()) {
                    // 处理不同类型的查询参数
                    if (parameter instanceof QueryWrapper) {
                        // 对于QueryWrapper，直接添加条件
                        QueryWrapper<?> queryWrapper = (QueryWrapper<?>) parameter;
                        queryWrapper.and(i -> i.apply(permissionSql));
                    } else {
                        // 对于原生SQL，修改SQL语句
                        String originalSql = boundSql.getSql();
                        String newSql = buildNewSql(originalSql, permissionSql);
                        // 使用反射修改boundSql的sql属性
                        reflectSetValue(boundSql, "sql", newSql);
                    }
                }
            } finally {
                // 清理上下文
                DataPermissionContext.clear();
            }
        }
    }

    /**
     * 获取参数数量
     */
    private int getParameterCount(Object parameter) {
        if (parameter == null) {
            return 0;
        }
        if (parameter instanceof Map) {
            Map<?, ?> paramMap = (Map<?, ?>) parameter;

            if (paramMap.containsKey(Constants.ENTITY)) {
                return 1;
            }
           /* Object entity = paramMap.get(Constants.ENTITY);
            if (entity != null) {
                return 1;
            }*/
            return paramMap.size();
        }
        return 1;
    }

    /**
     * 处理数据权限
     */
    private String processDataPermission(DataPermissionContext.DataPermissionInfo info) {
        // 获取对应的数据权限处理器
        DataPermissionHandler handler =
                dataPermissionHandlerFactory.getHandler(info.getType());

        if (handler != null) {
            return handler.handle(info);
        }
        return null;
    }

    /**
     * 构建新的SQL
     */
    private String buildNewSql(String originalSql, String permissionSql) {
        try {
            // 使用JSQLParser解析SQL
            Select select = (Select) CCJSqlParserUtil.parse(originalSql);
            PlainSelect plainSelect = (PlainSelect) select.getSelectBody();

            // 构建新的WHERE条件
            String whereClause = plainSelect.getWhere() != null ?
                    plainSelect.getWhere().toString() + " AND (" + permissionSql + ")" :
                    permissionSql;

            // 更新WHERE条件
            plainSelect.setWhere(CCJSqlParserUtil.parseCondExpression(whereClause));

            return plainSelect.toString();
        } catch (JSQLParserException e) {
            // 如果解析失败，使用简单方式处理
            int whereIndex = originalSql.toUpperCase().indexOf("WHERE");
            if (whereIndex > 0) {
                return originalSql.substring(0, whereIndex + 5) +
                        " (" + permissionSql + ") AND " +
                        originalSql.substring(whereIndex + 5);
            } else {
                return originalSql + " WHERE " + permissionSql;
            }
        }
    }

    /**
     * 使用反射设置值
     */
    private void reflectSetValue(Object obj, String fieldName, Object value) {
        try {
            java.lang.reflect.Field field = obj.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(obj, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean willDoQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds,
                               ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        return InnerInterceptor.super.willDoQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql);
    }

//    @Override
//    public void beforePrepare(Executor executor, MappedStatement ms, BoundSql boundSql) throws Exception {
//        InnerInterceptor.super.beforePrepare(executor, ms, boundSql);
//    }
}